package com.corpgovernment.permission.service.impl;

import com.corpgovernment.common.enums.ResourceEnum;
import com.corpgovernment.common.handler.ICacheHandler;
import com.corpgovernment.permission.controller.RoleRest;
import com.corpgovernment.permission.entity.db.MbPermission;
import com.corpgovernment.permission.entity.db.MbRoleResource;
import com.corpgovernment.permission.mapper.MbRoleResourceMapper;
import com.corpgovernment.permission.mapper.PermissionMapper;
import com.corpgovernment.permission.service.MbRoleResourceService;
import com.corpgovernment.permission.service.RoleResourceService;
import com.ctrip.corp.obt.generic.utils.CollectionUtils;
import com.ctrip.corp.obt.generic.utils.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author ：xks
 * @date ：Created in 2022/7/19 19:29
 * @description：
 * @modified By：
 * @version: $
 */
@Slf4j
@Service
public class MbRoleResourceServiceImpl implements MbRoleResourceService {

    @Autowired
    private MbRoleResourceMapper mbRoleResourceMapper;
    @Autowired
    private RoleResourceService roleResourceService;
    @Autowired
    private PermissionMapper permissionMapper;
    @Resource
    private ICacheHandler cacheHandler;

    @Override
    public List<MbRoleResource> findByRoleId(Long roleId) {
        Example example = new Example(MbRoleResource.class);
        example.createCriteria().andEqualTo("roleId", roleId).andEqualTo("deleteTime", new Date(0));
        return Optional.ofNullable(mbRoleResourceMapper.selectByExample(example)).orElse(new ArrayList<>());
    }

    @Override
    public List<Long> findRoleIdByOrgId(Long orgId) {
        Example example = new Example(MbRoleResource.class);
        example.createCriteria().andEqualTo("resourceId", orgId).andEqualTo("deleteTime", new Date(0));
        return Optional.ofNullable(mbRoleResourceMapper.selectByExample(example)).orElse(new ArrayList<>()).stream().map(MbRoleResource::getRoleId).collect(Collectors.toList());
    }

    @Override
    public void addOrUpdateInfo(Long roleId, List<Long> orgIdList, ResourceEnum resource) {
        List<MbRoleResource> byRoleId = this.findByRoleId(roleId);
        if (CollectionUtils.isEmpty(byRoleId)) {
            orgIdList.stream().forEach(a -> {
                mbRoleResourceMapper.insert(
                        MbRoleResource.builder()
                                .deleteTime(new Date(0))
                                .resourceId(a)
                                .type(resource.getCode())
                                .roleId(roleId).build());
            });
            return;
        }
        Set<Long> collect = byRoleId.stream().filter(a -> Objects.equals(resource.getCode(), a.getType())).map(MbRoleResource::getResourceId).collect(Collectors.toSet());
        List<Long> add = Optional.ofNullable(orgIdList.stream().filter(a -> !collect.contains(a)).collect(Collectors.toList())).orElse(new ArrayList<>());
        add.stream().forEach(a -> {
            mbRoleResourceMapper.insert(
                    MbRoleResource.builder()
                            .deleteTime(new Date(0))
                            .resourceId(a)
                            .type(resource.getCode())
                            .roleId(roleId).build());
        });

        List<Long> del = Optional.ofNullable(collect.stream().filter(a -> !new HashSet<>(orgIdList).contains(a)).collect(Collectors.toList())).orElse(new ArrayList<>());
        if (CollectionUtils.isNotEmpty(del)) {
            this.delRoleOrg(roleId, del, resource.getCode());
        }
        roleResourceService.empty(roleId);
    }


    @Override
    public void addOrUpdatePermissionInfo(Long roleId, List<Long> orgIdList) {
        List<MbRoleResource> byRoleId = this.findByRoleId(roleId);
        if (CollectionUtils.isEmpty(byRoleId)) {
            orgIdList.stream().forEach(a -> {
                mbRoleResourceMapper.insert(
                        MbRoleResource.builder()
                                .deleteTime(new Date(0))
                                .resourceId(a)
                                .type(ResourceEnum.PERMISSION.getCode())
                                .roleId(roleId).build());
            });
            return;
        }
        Set<Long> collect = byRoleId.stream().filter(a -> Objects.equals(ResourceEnum.PERMISSION.getCode(), a.getType())).map(MbRoleResource::getResourceId).collect(Collectors.toSet());
        List<Long> add = Optional.ofNullable(orgIdList.stream().filter(a -> !collect.contains(a)).collect(Collectors.toList())).orElse(new ArrayList<>());
        add.stream().forEach(a -> {
            mbRoleResourceMapper.insert(
                    MbRoleResource.builder()
                            .deleteTime(new Date(0))
                            .resourceId(a)
                            .type(ResourceEnum.PERMISSION.getCode())
                            .roleId(roleId).build());
        });

        List<Long> del = Optional.ofNullable(collect.stream().filter(a -> !new HashSet<>(orgIdList).contains(a)).collect(Collectors.toList())).orElse(new ArrayList<>());
        if (CollectionUtils.isNotEmpty(del)) {
            this.delRoleOrg(roleId, del, ResourceEnum.PERMISSION.getCode());
        }
        roleResourceService.empty(roleId);
    }

    @Override
    public void roleDataProcess(RoleRest.RoleInfo request) {
        //查询出对应菜单
        Example example = new Example(MbPermission.class);
        example.createCriteria().andEqualTo("resName", request.getRoleName()).andEqualTo("isDeleted", Boolean.FALSE);
        List<MbPermission> mbPermissions = permissionMapper.selectByExample(example);
        MbPermission mbPermission = mbPermissions.get(0);
        log.info("query-mbPermissions:{}", JsonUtils.toJsonString(mbPermission));

        //根据对应菜单ID找到所关联的所有角色
        Example e = new Example(MbRoleResource.class);
        e.createCriteria().andEqualTo("resourceId", mbPermission.getId()).andEqualTo("type", 2)
                .andEqualTo("deleteTime", new Date(0));
        List<MbRoleResource> mbRoleResources = mbRoleResourceMapper.selectByExample(e);
        log.info("query-mbRoleResources:{}", JsonUtils.toJsonString(mbRoleResources));
        //查询出当前对应菜单下所有的子级
        Example subExample = new Example(MbPermission.class);
        subExample.createCriteria().andEqualTo("parentId", mbPermission.getId()).andEqualTo("isDeleted", Boolean.FALSE);
        List<MbPermission> subPermissions = permissionMapper.selectByExample(subExample);
        log.info("query-subPermissions:{}", JsonUtils.toJsonString(subPermissions));
        //循环已经配置了当前菜单的所有角色
        for (MbRoleResource mbRoleResource : mbRoleResources) {
            //查询出当前角色所配置的所有菜单ID  交验是否已经配置  如已经配置则忽略未配置则新增权限
            Example roleAllPermissionsResourceExample = new Example(MbRoleResource.class);
            roleAllPermissionsResourceExample.createCriteria().andEqualTo("roleId", mbRoleResource.getRoleId()).andEqualTo("deleteTime", new Date(0));
            List<MbRoleResource> roleAllPermissionsResource = mbRoleResourceMapper.selectByExample(roleAllPermissionsResourceExample);

            Set<Long> roleAllPermissionsResourceSet = roleAllPermissionsResource.stream().map(MbRoleResource::getResourceId).collect(Collectors.toSet());
            //循环角色子级  如果当前配置不包含当前子级则新增  包含则忽略   -- 不管当前角色是否包含都清除缓存  auth-server会重新加载当前角色资源
            for (MbPermission subPermission : subPermissions) {
                if (!roleAllPermissionsResourceSet.contains(subPermission.getId())) {
                    log.info("当前角色:{}缺失:{}",mbRoleResource.getRoleId() , JsonUtils.toJsonString(subPermission));
                    mbRoleResourceMapper.insert(
                            MbRoleResource.builder()
                                    .deleteTime(new Date(0))
                                    .resourceId(subPermission.getId())
                                    .type(ResourceEnum.PERMISSION.getCode())
                                    .roleId(mbRoleResource.getRoleId()).build());
                }
            }
            cacheHandler.delete(String.format("ROLE_RESOURCE_%s_ROLEID", String.valueOf(mbRoleResource.getRoleId())));
        }

    }

    @Override
    public void addOneResource(Long roleId, Long resourceId, String orgId, String orgType, Integer type) {
        mbRoleResourceMapper.insert(
                MbRoleResource.builder()
                        .deleteTime(new Date(0))
                        .resourceId(resourceId)
                        .type(type)
                        .roleId(roleId).build());
        roleResourceService.addOneResource(roleId, resourceId, orgId, orgType, type);
    }

    @Override
    public void delRoleOrg(Long roleId, List<Long> orgIdList, Integer type) {
        Example example = new Example(MbRoleResource.class);
        example.createCriteria().andEqualTo("roleId", roleId).andIn("resourceId", orgIdList).andEqualTo("type", type);
        MbRoleResource mbRoleOrg = new MbRoleResource();
        mbRoleOrg.setDeleteTime(new Date());
        mbRoleOrg.setDatachangeLasttime(new Date());
        mbRoleResourceMapper.updateByExampleSelective(mbRoleOrg, example);
    }
}
